﻿using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Text.RegularExpressions;


/// <summary>
/// Read and write operations with Actie Directory
/// </summary>
public class ADrwInfo
{
    const string AccountDisabledFlag = @"1.2.840.113556.1.4.803:=2";        
    private string rootDSE = "";
    private string defaultnc = "";
    private string upnSuffix = "";

	public ADrwInfo()
	{
        using (DirectoryEntry de = new DirectoryEntry("LDAP://RootDSE"))
        {
            rootDSE = "LDAP://" + de.Properties["defaultNamingContext"][0].ToString();
            defaultnc = de.Properties["defaultNamingContext"][0].ToString();
            upnSuffix = Regex.Replace(defaultnc, "dc=", "", RegexOptions.IgnoreCase);
            upnSuffix = upnSuffix.Replace(',', '.');
        }
    }

    public string UpnSuffx
    {
        get
        {
            return upnSuffix;
        }
    }

    public List<ADobjInfo> RetObjValues(ref string objContentMsg, out int retval, out int objContentNO, string objsearchfilter, ADobjInfo adobjin)
    {
       
        retval = 0;
        string objfilter = "";
        List<ADobjInfo> rtnLst = new List<ADobjInfo>(); 
      
        switch (objsearchfilter)
        {
            case "user":
                objfilter = "(&(objectClass=User)(!(userAccountControl:" + AccountDisabledFlag + "))(samAccountName=" + adobjin.ADUserID + "))";
                break;
            case "mail":
                objfilter = "(&(objectClass=User)(!(userAccountControl:" + AccountDisabledFlag + "))(proxyAddresses=smtp:" + adobjin.ADMail + "))";
                break;
            case "personnelno":
                objfilter = "(&(objectClass=User)(!(userAccountControl:" + AccountDisabledFlag + "))(extensionAttribute5=" + adobjin.ADpersonnelNumber.ToString() + "))";
                break;
            case "name":
                objfilter = "(&(objectClass=User)(!(userAccountControl:" + AccountDisabledFlag + "))(name=" + adobjin.ADfullName + "))";
                break;
            case "firstfamilyname":
                objfilter = "(|" +
                        "(&(objectClass=Contact)(givenName=" + adobjin.ADfirstName + ")(sn=" + adobjin.ADfamilyName + "))" +
                        "(&(objectClass=User)(!(userAccountControl:" + AccountDisabledFlag + "))(givenName=" + adobjin.ADfirstName + ")(sn=" + adobjin.ADfamilyName + "))" +
                        ")";
                break;
        }
        
        try
        {       
            
            string[] myProps = new string[] { "distinguishedName", "extensionAttribute1", "sn", "proxyAddresses", "mail",
                "name", "givenName", "memberOf", "l", "postalCode", "samAccountName", "streetAddress", "extensionAttribute5" };

            using (DirectoryEntry entry = new DirectoryEntry(rootDSE))
            using (DirectorySearcher mySearcher = new DirectorySearcher(entry, objfilter, myProps))
            {
                using (SearchResultCollection result = mySearcher.FindAll())
                {
                    if (result.Count > 0)
                    {
                        string propertyName = "memberOf";

                        foreach (SearchResult rs in result)
                        {
                            ADobjInfo ADObj = new ADobjInfo();

                            ResultPropertyValueCollection valueCollection = rs.Properties[propertyName];
                            ADObj.ADmemberOf = new List<string>();

                            ADObj.ADdistinguishedName = rs.Properties["distinguishedName"][0].ToString();

                            if (rs.Properties["samAccountName"].Count > 0)
                                ADObj.ADUserID = rs.Properties["samAccountName"][0].ToString();
                            else
                                ADObj.ADUserID = "";

                            if (rs.Properties["name"].Count > 0)
                                ADObj.ADfullName = rs.Properties["name"][0].ToString();
                            else
                                ADObj.ADfullName = "";

                            if (rs.Properties["givenName"].Count > 0)
                                ADObj.ADfirstName = rs.Properties["givenName"][0].ToString();
                            else
                                ADObj.ADfirstName = "";

                            if (rs.Properties["sn"].Count > 0)
                                ADObj.ADfamilyName = rs.Properties["sn"][0].ToString();
                            else
                                ADObj.ADfamilyName = "";

                            if ((String.IsNullOrEmpty(valueCollection.ToString())))
                            {
                                ADObj.ADmemberOf.Add("");
                            }
                            else
                            {
                                if (valueCollection.Count > 0)
                                {
                                    for (int j = 0; j < valueCollection.Count - 1; j++)
                                    {
                                        ADObj.ADmemberOf.Add(valueCollection[j].ToString());
                                    }
                                }
                                else
                                {
                                    ADObj.ADmemberOf.Add("");
                                }
                            }

                            if ((String.IsNullOrEmpty(rs.Properties["extensionAttribute1"].ToString())))
                            {
                                ADObj.ADcompanyKey = "";
                            }
                            else
                            {
                                if (rs.Properties["extensionAttribute1"].Count > 0)
                                {
                                    ADObj.ADcompanyKey = rs.Properties["extensionAttribute1"][0].ToString();
                                }
                                else
                                {
                                    ADObj.ADcompanyKey = "";
                                }
                            }

                            if ((String.IsNullOrEmpty(rs.Properties["extensionAttribute5"].ToString())))
                            {
                                ADObj.ADpersonnelNumber = "";
                            }
                            else
                            {
                                if (rs.Properties["extensionAttribute5"].Count > 0)
                                {
                                    ADObj.ADpersonnelNumber = rs.Properties["extensionAttribute5"][0].ToString();
                                }
                                else
                                {
                                    ADObj.ADpersonnelNumber = "";
                                }
                            }

                            if ((String.IsNullOrEmpty(rs.Properties["streetAddress"].ToString())))
                            {
                                ADObj.ADstreetAddress = "";
                            }
                            else
                            {
                                if (rs.Properties["streetAddress"].Count > 0)
                                {
                                    ADObj.ADstreetAddress = rs.Properties["streetAddress"][0].ToString();
                                }
                                else
                                {
                                    ADObj.ADstreetAddress = "";
                                }
                            }

                            if ((String.IsNullOrEmpty(rs.Properties["postalCode"].ToString())))
                            {
                                ADObj.ADpostalCode = "";
                            }
                            else
                            {
                                if (rs.Properties["postalCode"].Count > 0)
                                {
                                    ADObj.ADpostalCode = rs.Properties["postalCode"][0].ToString();
                                }
                                else
                                {
                                    ADObj.ADpostalCode = "";
                                }
                            }

                            if ((String.IsNullOrEmpty(rs.Properties["l"].ToString())))
                            {
                                ADObj.ADCity = "";
                            }
                            else
                            {
                                if (rs.Properties["l"].Count > 0)
                                {
                                    ADObj.ADCity = rs.Properties["l"][0].ToString();
                                }
                                else
                                {
                                    ADObj.ADCity = "";
                                }
                            }

                            if ((String.IsNullOrEmpty(rs.Properties["mail"].ToString())))
                            {
                                ADObj.ADMail = "";
                            }
                            else
                            {
                                if (rs.Properties["mail"].Count > 0)
                                {
                                    ADObj.ADMail = rs.Properties["mail"][0].ToString();
                                }
                                else
                                {
                                    ADObj.ADMail = "";
                                }
                            }

                            rtnLst.Add(ADObj);
                        }

                        objContentNO = rtnLst.Count;
                        objContentMsg = "ok";

                    }
                    else
                    {
                        objContentMsg = "Searched object not found: " + adobjin.ADUserID + " " + adobjin.ADfirstName + " " + adobjin.ADfamilyName;
                        objContentNO = 0;
                    }                           
                }           
            }          
                        
            retval = 0;
        }

        catch (Exception ex)
        {
            objContentMsg += ex.Message + "\n" + ex.StackTrace;            
            objContentNO = 0;
            retval = 1;
        }

        return rtnLst;

    }
        
    public List<string> RetOUs(ref string objContentMsg, out int retval, out int objContentNO, bool OUfiltered)
    {

        retval = 0;
        string objfilter = "";
        List<string> rtnLst = new List<string>();

        objfilter = "(&(objectClass=organizationalUnit)(!isCriticalSystemObject=*))";

        try
        {

            string[] myProps = new string[] { "distinguishedName", "name" };

            using (DirectoryEntry entry = new DirectoryEntry(rootDSE))
            using (DirectorySearcher mySearcher = new DirectorySearcher(entry, objfilter, myProps))
            {
                mySearcher.PageSize = 2000;
                using (SearchResultCollection result = mySearcher.FindAll())
                {
                    foreach (SearchResult rs in result)
                    {
                        rtnLst.Add(rs.Properties["distinguishedName"][0].ToString());
                    }

                    List<string> OUSorted = new List<string>();
                    foreach (string itm in rtnLst)
                    {
                        string[] tmparr = itm.Split(',');
                        Array.Reverse(tmparr);
                        StringBuilder sb = new StringBuilder();
                        for (int i = 0; i < tmparr.Length; i++)
                        {
                            sb.Append(tmparr[i]).Append(",");
                        }
                        if (OUfiltered)
                        {
                            if ((sb.ToString().ToLower().Contains("users")) && 
                                (!sb.ToString().ToLower().Contains("administrative")) &&
                                (!sb.ToString().ToLower().Contains("gpo-test")) && 
                                (!sb.ToString().ToLower().Contains("disabled")))
                                OUSorted.Add(sb.ToString().Substring(0, sb.ToString().Length - 1));
                        }
                        else
                        {
                            OUSorted.Add(sb.ToString().Substring(0, sb.ToString().Length - 1));
                        }
                    }
                    OUSorted.Add("_Please choose:");
                    OUSorted.Sort();
                    rtnLst.Clear();                    
                    rtnLst = OUSorted;

                    objContentNO = rtnLst.Count;
                    objContentMsg = "ok";

                    retval = 0;
                }                
            }                        
        }

        catch (Exception ex)
        {
            objContentMsg += ex.Message + "\n" + ex.StackTrace;
            objContentNO = 0;
            retval = 1;
        }

        return rtnLst;

    }     

    public void CreateUser(out string objContentMsg, out int retval, ADobjInfo adobjin)
    {
        retval = 0;
        objContentMsg = "";

        string ouname = WbVarious.FormatDN(adobjin.ADdistinguishedName);                
        string usrrdn = "CN=" + adobjin.ADfullName.Replace(",", "\\,");
        string usrupn = adobjin.ADUserID.ToUpper() + '@' + upnSuffix;
        
        try
        {
            rootDSE = "LDAP://" + ouname;
            using (DirectoryEntry adentry = new DirectoryEntry(rootDSE))
            using (DirectoryEntry User = adentry.Children.Add(usrrdn, "user"))
            {

                User.Properties["displayName"].Add(adobjin.ADfullName);
                User.Properties["givenName"].Add(adobjin.ADfirstName);
                User.Properties["sn"].Add(adobjin.ADfamilyName);

                if (!String.IsNullOrEmpty(adobjin.ADUserID))
                {
                    User.Properties["sAMAccountName"].Add(adobjin.ADUserID.ToUpper());
                    User.Properties["userPrincipalName"].Add(usrupn);
                }
                if (!String.IsNullOrEmpty(adobjin.ADcompanyKey))
                    User.Properties["extensionAttribute1"].Add(adobjin.ADcompanyKey);
                if (!String.IsNullOrEmpty(adobjin.ADpersonnelNumber))
                    User.Properties["extensionAttribute5"].Add(adobjin.ADpersonnelNumber);
                if (!String.IsNullOrEmpty(adobjin.ADSkype))
                    User.Properties["pager"].Add(adobjin.ADSkype);
                if (!String.IsNullOrEmpty(adobjin.ADCity))
                    User.Properties["l"].Add(adobjin.ADCity);
                if (!String.IsNullOrEmpty(adobjin.ADpostalCode))
                    User.Properties["postalCode"].Add(adobjin.ADpostalCode);
                if (!String.IsNullOrEmpty(adobjin.ADstreetAddress))
                    User.Properties["streetAddress"].Add(adobjin.ADstreetAddress);
                if (!String.IsNullOrEmpty(adobjin.ADtelelphoneNumber))
                    User.Properties["telephoneNumber"].Add(adobjin.ADtelelphoneNumber);

                if (!String.IsNullOrEmpty(adobjin.ADproxyAddresses))
                {
                    if (adobjin.ADproxyAddresses.Contains("_"))                        
                        User.Properties["proxyAddresses"].AddRange(new object[] { "DIR:" + adobjin.ADproxyAddresses });
                    else                    
                        User.Properties["facsimileTelephoneNumber"].Add(adobjin.ADproxyAddresses);                    
                }
                                        
                if (!String.IsNullOrEmpty(adobjin.ADPwd))
                {
                    User.CommitChanges();
                    User.Invoke("SetPassword", new object[] { adobjin.ADPwd });
                    User.CommitChanges();
                    User.Properties["pwdLastSet"].Value = 0;
                    int val = (int)User.Properties["userAccountControl"].Value;
                    User.Properties["userAccountControl"].Value = val & ~0x2;
                    User.CommitChanges();
                    User.RefreshCache();
                }

                if (!String.IsNullOrEmpty(adobjin.ADExperiationDate.ToString()))
                {
                    if (adobjin.ADExperiationDate > DateTime.Today)
                    {
                        int ayear = adobjin.ADExperiationDate.Year;
                        int amonth = adobjin.ADExperiationDate.Month;
                        int aday = adobjin.ADExperiationDate.Day;

                        DateTime dt = new DateTime(ayear, amonth, aday);

                        if (adobjin.ADTimeOffset < 0)
                        {
                            dt = dt.AddDays(2);
                        }


                        if ((adobjin.ADTimeOffset < 12) && adobjin.ADTimeOffset > 1) 
                        {
                            dt = dt.AddDays(1); 
                        }

                        if (adobjin.ADTimeOffset != 0)
                        {
                            dt = dt.AddHours(adobjin.ADTimeOffset);
                        }
                        
                        User.InvokeSet("AccountExpirationDate", dt);
                        User.CommitChanges();
                    }
                }
                    
                retval = 0;
            }
        }
        catch (Exception ex)
        {
            objContentMsg += ex.Message + "\n" + ex.StackTrace;
            retval = 1;
        }     

    }

    public void AddUserToGroups(out string objContentMsg, out int retval, ADobjInfo adobjin)
    {
        retval = 0;        
        objContentMsg = "";       

        try
        {
            string ouname = WbVarious.FormatDN(adobjin.ADdistinguishedName); 
            string usrrdn = "CN=" + adobjin.ADfullName.Replace(",", "\\,");
            string usrdn = usrrdn + ',' + ouname;
   
            List<string> groups = adobjin.ADmemberOf;
            if ((groups.Count > 0) && (!String.IsNullOrEmpty(groups[0])))
            {
                foreach (string group in groups)
                {
                    if (ADObjCheckWritePermission("LDAP://" + group))
                    {
                        using (DirectoryEntry adentry = new DirectoryEntry("LDAP://" + group))
                        {
                            adentry.Properties["member"].Add(usrdn);
                            adentry.CommitChanges();
                            adentry.Close();
                        }
                    }
                    else
                    {
                        objContentMsg += "Not having write access to group: " + group + "<br />";
                    }
                }                
            }
            retval = 0;   
        }
        catch (Exception ex)
        {
            objContentMsg += ex.Message + "\n" + ex.StackTrace;            
            retval = 1;
        }        

    }

    public bool ADObjCheckWritePermission(string distingusihedname)
    {
        using (DirectoryEntry adentry = new DirectoryEntry(distingusihedname))
        {
            adentry.RefreshCache(new string[] { "allowedAttributesEffective" });
            return adentry.Properties["allowedAttributesEffective"].Value != null;
        }
    }

    public bool ADObjExists(string distinguishedname)
    {
        bool found = false;
        if (DirectoryEntry.Exists(distinguishedname))
            found = true;
        return found;
    }

    public string GetUsrSID(string samAccountName, out int retval, out string objMsg)
    {
        retval = 1;
        objMsg = "";
        string userSid = "";

        PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
        UserPrincipal user = UserPrincipal.FindByIdentity(ctx, samAccountName);

        if (user != null)
        {
            userSid = user.Sid.ToString();
            objMsg = "User " + samAccountName + " found.";
            retval = 0;
        }
        else
        {
            objMsg = "User " + samAccountName + " not found!";
            retval = 1;
        }

        return userSid;
    }


}